<script lang="ts" setup>
import {ref} from "vue"
import {useUserStore} from "@/stores/user";
import {onShow, onUnload} from "@dcloudio/uni-app";
import type {ChatMessage, ChatSendItem} from "@/interface/Chat";
import {getChatHistoryListApi, getChatLinkIdApi} from "@/api/chat";
import {formatTimeDifference} from "@/utils/time";
import {WS_URL} from "@/constant/websocketConstant";

onUnload(() => {
  // 当用户离开聊天界面关闭连接并通知服务端修改当前聊天列表状态
  uni.closeSocket({
    code: 1000,
    reason: linkId.value ? linkId.value.toString() : '',
  })
})

onShow(() => {
  if (!userStore.userInfoData?.token) {
    return
  }
  console.log('连接websocket')
 uni.connectSocket({
    url: 'ws://'+WS_URL+'/ws/chat?userId=' + userStore.userInfoData?.userID + '&token=' + userStore.userInfoData.token + '&chatUserId=' + props.receiverId,
    header: {
      'content-type': 'application/json',
    },
    success: () => {
      console.log('WebSocket连接创建成功！')
    }
  })
})

const props = defineProps<{
  receiverId?: string
  receiverName?: string
  receiverAvatar?: string
  linkId?: string
}>()
const linkId = ref<number>(props.linkId ? parseInt(props.linkId) : -1)
const userStore = useUserStore()
const dataList = ref<ChatMessage[]>([])
const paging = ref()
const inputBar = ref()

const addChat = (chat: ChatMessage) => {
  try {
    paging.value.addChatRecordData([chat])
  } catch (e) {
    // uni重新加载此页面
  }
}

const getChatHistoryList = async (page: number, pageSize: number): Promise<ChatMessage[]> => {
  // TODO 获取本地存储数据（不管本地有无数据都需发送一个请求确认消息）
  const {data: {data}} = await getChatHistoryListApi(page, pageSize, Number(props.receiverId), Number(props.linkId))
  if (data === null || data.length === 0) {
    return []
  }
  data.forEach((item: ChatMessage) => {
    item.originTime = item.time
  })
  // 创建一个新的数组来存储处理后的结果
  let result: ChatMessage[] = [];

// 遍历排序后的数组
  for (let i = 0; i < data.length; i++) {
    // 如果是第一条元素，直接加入结果数组
    if (i === data.length - 1) {
      result.push(data[i])
    } else if (i === 0) {
      result.push(data[i])
    } else {
      let timeDiff: number
      // 计算当前元素与上一条元素的时间差（单位：毫秒）
      timeDiff = new Date(data[i].time).getTime() - new Date(data[i - 1].time).getTime()
      // 如果时间差大于3分钟（3*60*1000毫秒），则加入结果数组
      if (-timeDiff > 3 * 60 * 1000) {
        result.push(data[i]);
      } else {
        // 如果时间差小于等于3分钟，则只显示第一条元素的时间
        data[i].time = ''
        result.push(data[i])
      }
    }
  }

  return result.map((item) => {
    item.time = item.time ? formatTimeDifference(Date.parse(item.time), Date.now()) : ''
    if (item.isMe) {
      item.icon = userStore.userInfoData!.avatarURL
      item.name = userStore.userInfoData!.username
    } else {
      item.icon = props.receiverAvatar!
      item.name = props.receiverName!
    }
    return item
  })
}

const queryList = async (pageNo: number, pageSize: number) => {
  uni.setNavigationBarTitle({title: props.receiverName})
  // webSocket消息的接收必须放在此方法中
  uni.onSocketMessage(async (res) => {
    let time = ''
    if (dataList.value.length > 0) {
      time = Date.now() - Date.parse(dataList.value[0]?.originTime) > 3 * 60 * 1000 ? formatTimeDifference(Date.now(), Date.now()) : ''
    }
    const chat: ChatMessage = {
      time: time,
      originTime: new Date().toLocaleDateString(),
      icon: props.receiverAvatar!,
      name: props.receiverName!,
      content: res.data,
      isMe: false
    }
    addChat(chat)
  })
  // getWebSocketLink()
  // 组件加载时会自动触发此方法，因此默认页面加载时会自动触发，无需手动调用
  // 这里的pageNo和pageSize会自动计算好，直接传给服务器即可

  try {
    const res = await getChatHistoryList(pageNo, pageSize)
    paging.value.complete(res)
  } catch (e) {
    paging.value.complete(false)
  }

}

// 监听键盘高度改变，请不要直接通过uni.onKeyboardHeightChange监听，否则可能导致z-paging内置的键盘高度改变监听失效（如果不需要切换表情面板则不用写）
const keyboardHeightChange = (res: any) => {
  inputBar.value.updateKeyboardHeightChange(res)
}

// 用户尝试隐藏键盘，此时如果表情面板在展示中，应当通知chatInputBar隐藏表情面板（如果不需要切换表情面板则不用写）
const hidedKeyboard = () => {
  inputBar.value.hidedKeyboard()
}
// 发送新消息
const doSend = async (msg: string) => {
  // uni.showLoading({
  //   title: '发送中...'
  // })
  const chatItem: ChatSendItem = {
    senderId: userStore.userInfoData!.userID,
    receiverId: Number(props.receiverId),
    linkId: linkId.value || -1,
    content: msg,
    type: 0,
    senderName: userStore.userInfoData!.username
  }
  await uni.sendSocketMessage({
    data: JSON.stringify(chatItem),
  })
  let time = Date.now() - Date.parse(dataList.value[dataList.value.length - 1]?.originTime) > 3 * 60 * 1000 ? formatTimeDifference(Date.now(), Date.now()) : ''
  paging.value.addChatRecordData([{
    time: time,
    icon: userStore.userInfoData?.avatarURL || '/static/kun.png',
    name: userStore.userInfoData!.username,
    content: msg,
    isMe: true
  }])
  if (linkId.value === -1 || linkId.value === null || linkId.value === undefined) {
    // 该用户之前和该人没有聊天记录，但用户进行了聊天，获取聊天后生成的linkId
    const {data} = await getChatLinkIdApi(Number(props.receiverId))
    linkId.value = data
  }
}
</script>
<!-- 聊天记录模式+虚拟列表演示(vue)，加载更多聊天记录无闪动&支持渲染大量数据 -->
<!-- 注意：虚拟列表缓存高度默认仅在cell初始化时获取一次，若您的聊天列表中带有图片，强烈建议给图片一个固定的高度，如果高度根据内容动态撑高，可能导致虚拟列表抖动 -->
<!-- 如果必须实现高度根据内容动态撑高+虚拟列表功能，可监听图片加载完毕事件，并在其中调用z-paging的didUpdateVirtualListCell刷新缓存高度 -->
<template>
  <view class="content">
    <!-- use-chat-record-mode：开启聊天记录模式 -->
    <!-- use-virtual-list：开启虚拟列表模式 -->
    <!-- cell-height-mode：设置虚拟列表模式高度不固定 -->
    <!-- safe-area-inset-bottom：开启底部安全区域适配 -->
    <!-- bottom-bg-color：设置slot="bottom"容器的背景色，这里设置为和chat-input-bar的背景色一致 -->
    <z-paging ref="paging" v-model="dataList" :bottom-bg-color="'#f8f8f8'" cell-height-mode="dynamic"
              safe-area-inset-bottom
              use-chat-record-mode use-virtual-list
              @hidedKeyboard="hidedKeyboard"
              @keyboardHeightChange="keyboardHeightChange"
              @query="queryList">
      <!-- 顶部提示文字 -->
      <!--			<template #top>
              <view class="header">聊天记录总条数：10万条</view>
            </template>-->

      <!-- style="transform: scaleY(-1)"必须写，否则会导致列表倒置！！！ -->
      <!-- 注意不要直接在chat-item组件标签上设置style，因为在微信小程序中是无效的，请包一层view -->
      <template #cell="{item,index}">
        <view style="transform: scaleY(-1)">
          <chat-item :item="item"></chat-item>
        </view>
      </template>

      <!-- 底部聊天输入框 -->
      <template #bottom>
        <chat-input-bar ref="inputBar" @send="doSend"/>
      </template>
      <template #empty></template>
    </z-paging>
  </view>
</template>


<style scoped>
/* #ifdef H5 */
body {
  background-color: #F0F2F4;
}

/* #endif */

.content {
}
</style>
